package com.youlu.campus.service.jinshuju;

import cn.hutool.core.util.ZipUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.entity.*;
import com.youlu.campus.entity.VO.req.CaptchaRequest;
import com.youlu.campus.entity.dto.sms.SmsBaseInfoDTO;
import com.youlu.campus.entity.jinshuju.JinUserBindInfo;
import com.youlu.campus.entity.jinshuju.JinUserParticipate;
import com.youlu.campus.entity.jinshuju.JinUserRank;
import com.youlu.campus.entity.jinshuju.dto.*;
import com.youlu.campus.entity.jinshuju.vo.JinUserInfoQueryVo;
import com.youlu.campus.entity.jinshuju.vo.JinUserWechatVO;
import com.youlu.campus.entity.jinshuju.vo.QueryIndexVO;
import com.youlu.campus.service.activity.*;
import com.youlu.campus.service.cache.CacheUserService;
import com.youlu.campus.service.file.FileExportTaskService;
import com.youlu.campus.service.file.FileService;
import com.youlu.campus.service.platform.PlatformConfigService;
import com.youlu.campus.service.qa.ActivityQaInfoService;
import com.youlu.campus.service.sms.SmsServerService;
import com.youlu.campus.service.tencentcloud.TencentCloudCaptchaService;
import com.youlu.campus.service.visitor.UserBlackListService;
import com.youlu.campus.service.visitor.VisitorUserService;
import com.youlu.campus.service.wechat.SystemNickNameAndHeaderImageService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author : [dengbo]
 * @className : JinUserActivityService
 * @description : [金数据服务]
 * @createTime : [2023/6/13 16:39]
 */
@Service
@Slf4j
public class JinShuJuUserActivityService {

    @Autowired
    private CacheUserService cacheUserService;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private VisitorUserService visitorUserService;

    @Autowired
    private SmsServerService smsServerService;

    @Autowired
    private ActivityQaInfoService activityQaInfoService;

    @Lazy
    @Autowired
    private JinShuJuActivityService jinShuJuActivityService;

    @Lazy
    @Autowired
    private JinShuJuQaService jinShuJuQaService;

    @Autowired
    private JinShuJuUserInviteService jinShuJuUserInviteService;

    @Autowired
    private JinShuJuUserRankService jinShuJuUserRankService;

    @Autowired
    private PlatformConfigService platformConfigService;

    @Autowired
    private SystemNickNameAndHeaderImageService systemNickNameAndHeaderImageService;

    @Autowired
    private TencentCloudCaptchaService tencentCloudCaptchaService;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private UserParticipateActivityInfoService userParticipateActivityInfoService;

    private final Integer MAX_COUNT = 500000;

    @Autowired
    private FileExportTaskService fileExportTaskService;

    @Autowired
    private FileService fileService;

    @Autowired
    private JinShuJuShortUrlService jinShuJuShortUrlService;

    @Lazy
    @Autowired
    private ActivityChannelStatisticsService activityChannelStatisticsService;
    @Lazy
    @Autowired
    private ActivitySubscribeAppIdService activitySubscribeAppIdService;
    @Autowired
    private UserBlackListService userBlackListService;
    @Lazy
    @Autowired
    private UserActivityTaskRankingAttachService userActivityTaskRankingAttachService;

    public void updateUserInfo(UpdateJinUserInfoDTO updateUserInfo) {
        UserPO currentUser = updateUserInfo.getCurrentUser();
        log.info("【更新用户信息】mobile:{},activityId:{}", currentUser.getMobile(), updateUserInfo.getActivityId());
        Query query = new Query();
        query.addCriteria(Criteria.where("mobile").is(currentUser.getMobile()));
        query.addCriteria(Criteria.where("activityId").is(updateUserInfo.getActivityId()));
        JinUserParticipate jinUserParticipate = this.mongoTemplate.findOne(query, JinUserParticipate.class);
        if (Objects.isNull(jinUserParticipate)) {
            throw new BusinessException("对不起，该活动您未报名,不能修改信息");
        }
        Update update = new Update();
        update.set("name", updateUserInfo.getName());
        update.set("universityName", updateUserInfo.getUniversityName());
        update.set("universityId", updateUserInfo.getActivityId());
        update.set("updatedTime", new Date());
        this.mongoTemplate.updateMulti(query, update, JinUserParticipate.class);
        jinUserParticipate.setName(updateUserInfo.getName());
        jinUserParticipate.setUniversityId(updateUserInfo.getUniversityId());
        jinUserParticipate.setUniversityName(updateUserInfo.getUniversityName());
        this.updateJinUserParticipate(jinUserParticipate);
    }


    public void export(JinUserParticipateQueryDTO dto) {
        String activityId = dto.getActivityId();
        ActivityInfo activityInfo = activityService.findOne(activityId);
        Integer currentPageNo = 1;
        Integer pageSize = 10000;
        log.info("【导出金数据活动参与报名用户信息】start activityId:{}", activityId);
        Integer count = 0;
        List<ExportJinUserParticipateDTO> exportResult = Lists.newLinkedList();
        while (true) {
            log.info("【导出金数据活动参与报名用户信息】正在导出 ..... 第" + currentPageNo + "页  start");
            dto.setPageNo(currentPageNo);
            dto.setPageSize(pageSize);
            Page<JinUserParticipate> jinUserPage = this.list(dto);
            List<JinUserParticipate> list = jinUserPage.getContent();
            if (CollectionUtils.isEmpty(list)) {
                log.info("【导出金数据活动参与报名用户信息】正在导出 ..... 第" + currentPageNo + "页  分页获取数据结束 end");
                break;
            }
            List<ExportJinUserParticipateDTO> result = list.stream().map(jinUserParticipate -> {
                log.info("导出数据为:{},手机号:{}", jinUserParticipate.getMobile(), JSON.toJSON(jinUserParticipate));
                ExportJinUserParticipateDTO exportJinUserParticipateDTO = new ExportJinUserParticipateDTO();
                exportJinUserParticipateDTO.setName(jinUserParticipate.getName());
                exportJinUserParticipateDTO.setMobile(jinUserParticipate.getMobile());
                exportJinUserParticipateDTO.setOpenId(jinUserParticipate.getOpenId());
                if (StringUtils.isNotBlank(jinUserParticipate.getUniversityName())) {
                    if (jinUserParticipate.getUniversityName().length() > 3000) {
                        log.info(":>>> 大学名字大于3000,手机号为:{}", jinUserParticipate.getMobile());
                        String s = jinUserParticipate.getUniversityName().substring(0, 50);
                        exportJinUserParticipateDTO.setUniversity("");
                    } else {
                        exportJinUserParticipateDTO.setUniversity(jinUserParticipate.getUniversityName());
                    }
                }
                exportJinUserParticipateDTO.setQaScore(jinUserParticipate.getScore());
                exportJinUserParticipateDTO.setQaTime(jinUserParticipate.getQaTime());
                exportJinUserParticipateDTO.setInviteCount(jinUserParticipate.getInviteSuccessNum());
                exportJinUserParticipateDTO.setPoints(jinUserParticipate.getCurrentQ());
                exportJinUserParticipateDTO.setSignUpTime(jinUserParticipate.getSignUpTime());
                Boolean existsMobile = userBlackListService.existsByMobile(jinUserParticipate.getMobile());
                if (existsMobile) {
                    exportJinUserParticipateDTO.setBackList("是");
                }
                return exportJinUserParticipateDTO;
            }).collect(Collectors.toList());
            exportResult.addAll(result);
            currentPageNo++;
        }
        count = exportResult.size();
        List<ExportJinUserParticipateDTO> exportResult2 = null;
        Integer skip = 0;
        String fileDirName = activityId + "-" + System.currentTimeMillis();
        File fileDir = new File("/data/app/file/" + fileDirName);
        if (!fileDir.exists()) {
            fileDir.mkdir();
        }
        try {
            ExcelWriter excelWriter = null;
            do {
                String fileName =
                        activityInfo.getName() + "-" + System.currentTimeMillis() + ExcelTypeEnum.XLSX.getValue();
                String file = "/data/app/file/" + fileDirName + "/" + fileName;
                exportResult2 = exportResult.stream().skip(skip * MAX_COUNT).limit(MAX_COUNT).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(exportResult2)) {
                    break;
                } else {
                    excelWriter = EasyExcel.write(file, ExportJinUserParticipateDTO.class).build();
                    WriteSheet writeSheet = EasyExcel.writerSheet(1, "用户参与报名信息").build();
                    excelWriter.write(exportResult2, writeSheet);
                }
                if (Objects.nonNull(excelWriter)) {
                    excelWriter.finish();
                }
                skip++;
            } while (Objects.nonNull(exportResult2) && !exportResult2.isEmpty());

        } catch (Exception e) {
            log.info("【导出金数据活动参与报名用户信息】error ", e);
            return;
        } finally {
            exportResult.clear();
            if (CollectionUtils.isNotEmpty(exportResult2)) {
                exportResult2.clear();
            }
        }
        log.info("【导出金数据活动参与报名用户信息】start 压缩文件夹 activityId:{}", activityId);
        FileExportTask fileExportTask = new FileExportTask();
        fileExportTask.setToken(dto.getOptUserName());
        fileExportTask.setBizType("jin-user-sign-up");
        fileExportTask.setStatus(0);
        fileExportTask.setOptUser(dto.getOptUserName());
        fileExportTask.setOptUser(dto.getOptUserName());
        fileExportTask.setOptUserId(dto.getOptUserId());
        fileExportTask.setFileName(activityInfo.getName() + "-用户参与人报名信息");
        fileExportTask.setNum(count);
        fileExportTask.setDesc(activityInfo.getName() + "-用户参与人报名信息");
        String fileExportTaskId = fileExportTaskService.create(fileExportTask);
        //压缩文件夹
        ZipUtil.zip(fileDir);
        InputStream in = null;
        try {
            File newFile = new File("/data/app/file/" + fileDirName + ".zip");
            if (!newFile.exists()) {
                log.error("找不到导出报名信息文件");
                return;
            }
            in = new FileInputStream(newFile);
            String url = fileService.uploadFile(in, fileDirName + ".zip");
            Query queryTask = new Query().addCriteria(Criteria.where("id").is(fileExportTaskId));
            Update update = new Update();
            update.set("status", 1);
            update.set("url", url);
            update.set("updatedTime", new Date());
            mongoTemplate.updateFirst(queryTask, update, FileExportTask.class);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            log.error("导出金数据活动参与报名用户信息 error", e);
            return;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("导出金数据活动参与报名用户信息 error", e);
            return;
        } finally {
            if (Objects.nonNull(in)) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        log.info("【导出金数据活动参与报名用户信息】end");


    }


    public JinShuJuActivityInviteDTO findInviteInfoByActivityId(String activityId, String platform, UserPO user) {
        JinShuJuActivityInviteDTO dto = jinShuJuActivityService.findInviteInfoByActivityId(activityId);
        ActivityInfo activityInfo = activityService.findOne(activityId);
        JinUserWechatVO wechatInfo = this.findWechatInfo(user, platform);
        dto.setNickName(wechatInfo.getNickName());
        dto.setAvatarUrl(wechatInfo.getAvatarUrl());
        dto.setAuthorized(wechatInfo.getAuthorized());
        StringBuilder path = new StringBuilder();
        path.append("/index.html?a=1#/pages/index?shareUserId=");
        path.append(user.getId());
        path.append("&activityId=");
        path.append(activityId);
        path.append("&scope=snsapi_base");
        if (Objects.nonNull(activityInfo) && StringUtils.isNotBlank(activityInfo.getWechatAppId())) {
            path.append("&appId=" + activityInfo.getWechatAppId());
        }
        dto.setShareUserId(user.getId());
        String shortUrl = jinShuJuShortUrlService.generateShortUrl(activityId, path.toString());
        dto.setShareUrl(shortUrl);
        return dto;
    }

    public JinUserParticipate detail(String id) {
        JinUserParticipate participate = this.mongoTemplate.findById(id, JinUserParticipate.class);
        JinUserRank rank = jinShuJuUserRankService.findByUserId(participate.getActivityId(), participate.getUserId());
        if (rank != null) {
            if (StringUtils.isBlank(participate.getOpenId())) {
                participate.setOpenId(rank.getOpenId());
            }
            participate.setInviteTotalNum(rank.getInviteNum());
            participate.setInviteSuccessNum(rank.getInviteNum());
            participate.setInviteScore(rank.getScore());
            participate.setQuantity(rank.getScore());
            participate.setCurrentQ(rank.getScore());
            participate.setRankAvatarUrl(rank.getRankAvatarUrl());
            participate.setRankNickName(rank.getRankNickName());
        }
        return participate;
    }

    public void updateJinUserParticipate(JinUserParticipate updateJinUserParticipate) {
        if (StringUtils.isBlank(updateJinUserParticipate.getId())) {
            throw new BusinessException("报名Id不存在");
        }
        JinUserParticipate participate = mongoTemplate.findById(updateJinUserParticipate.getId(), JinUserParticipate.class);
        Date now = new Date();
        if (participate == null) {
            throw new BusinessException("报名信息不存在");
        }
        updateJinUserParticipate.setMobile(participate.getMobile());
        updateJinUserParticipate.setUpdatedTime(now);
        this.mongoTemplate.save(updateJinUserParticipate);
        JinUserRank rank = jinShuJuUserRankService.findByUserId(updateJinUserParticipate.getActivityId(), updateJinUserParticipate.getUserId());
        if (rank != null) {
            rank.setDeleted(!updateJinUserParticipate.getJoinRank());
            rank.setRankAvatarUrl(updateJinUserParticipate.getRankAvatarUrl());
            rank.setRankNickName(updateJinUserParticipate.getRankNickName());
            rank.setUniversityId(updateJinUserParticipate.getUniversityId());
            rank.setUniversityName(updateJinUserParticipate.getUniversityName());
            rank.setName(updateJinUserParticipate.getName());
            rank.setUpdatedTime(new Date());
            if (updateJinUserParticipate.getQuantity() != null && updateJinUserParticipate.getQuantity() != 0) {
                int score = updateJinUserParticipate.getQuantity() + rank.getScore();
                if (score > 0) {
                    rank.setScore(score);
                    rank.setDeleted(false);
                } else {
                    rank.setScore(0);
                    rank.setDeleted(true);
                }
            }
            mongoTemplate.save(rank);
        } else {
            if (updateJinUserParticipate.getJoinRank() && updateJinUserParticipate.getQuantity() != null && updateJinUserParticipate.getQuantity() != 0) {
                int score = updateJinUserParticipate.getQuantity();
                if (score > 0) {
                    // 添加记录
                    rank = new JinUserRank();
                    rank.setActivityId(participate.getActivityId());
                    rank.setUserId(participate.getUserId());
                    rank.setMobile(participate.getMobile());
                    rank.setUniversityName(updateJinUserParticipate.getUniversityName());
                    rank.setUniversityId(updateJinUserParticipate.getUniversityId());
                    rank.setName(updateJinUserParticipate.getName());
                    rank.setRankAvatarUrl(updateJinUserParticipate.getRankAvatarUrl());
                    rank.setRankNickName(updateJinUserParticipate.getRankNickName());
                    rank.setDeleted(!updateJinUserParticipate.getJoinRank());
                    H5UserPO po = mongoTemplate.findOne(new Query(Criteria.where("mobile").is(participate.getMobile())), H5UserPO.class);
                    if (po != null) {
                        rank.setNickName(po.getNickName());
                        rank.setAvatarUrl(po.getAvatarUrl());
                    }
                    rank.setScore(score);
                    rank.setDeleted(false);
                    rank.setInviteNum(0);
                    rank.setCreatedTime(new Date());
                    rank.setUpdatedTime(new Date());
                    mongoTemplate.save(rank);
                }
            }

        }
    }


    /**
     * 金数据-后台admin 用户报名列表
     *
     * @param dto
     * @return
     */
    public Page<JinUserParticipate> list(JinUserParticipateQueryDTO dto) {
        String mobile = dto.getMobile();
        String name = dto.getName();
        String activityId = dto.getActivityId();
        Query query = new Query();
        query.addCriteria(Criteria.where("activityId").is(activityId));
        if (StringUtils.isNotBlank(mobile)) {
            query.addCriteria(Criteria.where("mobile").is(mobile));
        }
        if (StringUtils.isNotBlank(name)) {
            Pattern pattern = Pattern.compile("^.*" + name + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("name").regex(pattern));
        }
        long count = this.mongoTemplate.count(query, JinUserParticipate.class);
        PageRequest pageRequest = PageRequest.of(dto.getPageNo() - 1, dto.getPageSize());
//        query.with(new Sort(Sort.Direction.DESC, "createdTime"));
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        List<JinUserParticipate> list = this.mongoTemplate.find(query.with(pageRequest), JinUserParticipate.class);
        List<String> userIds = list.stream().map(JinUserParticipate::getUserId).collect(Collectors.toList());
        List<JinUserRank> ranks = jinShuJuUserRankService.findByUserIds(dto.getActivityId(), userIds);
        Map<String, JinUserRank> rankMap = ranks.stream().collect(Collectors.toMap(JinUserRank::getUserId, Function.identity(), (o1, o2) -> o2));
        list.stream().forEach(participate -> {
            JinUserRank rank = rankMap.get(participate.getUserId());
            if (rank != null) {
                participate.setInviteTotalNum(rank.getInviteNum());
                participate.setInviteSuccessNum(rank.getInviteNum());
                participate.setRankAvatarUrl(rank.getRankAvatarUrl());
                participate.setRankNickName(rank.getRankNickName());
                List<UserActivityTaskRankingAttach> attaches = userActivityTaskRankingAttachService.findAll(rank.getUserId(), rank.getActivityId());
                Integer q = rank.getScore();
                if (Objects.nonNull(attaches)) {
                    for (UserActivityTaskRankingAttach ua : attaches) {
                        if (Objects.nonNull(ua.getQuantity())) {
                            q = q + ua.getQuantity().intValue();
                        }
                    }
                }
                participate.setCurrentQ(q);
                participate.setInviteScore(q);
                if (StringUtils.isBlank(participate.getOpenId())) {
                    participate.setOpenId(rank.getOpenId());
                }
            }
        });
        return PageableExecutionUtils.getPage(list, pageRequest, () -> count);
    }


    public QueryUserJinShuJuResultDTO queryUserSignUpInfo(QueryIndexVO queryIndex) {
        String activityId = queryIndex.getActivityId();
        String mobile = queryIndex.getMobile();
        log.info("用户：{}查询活动：{}报名信息", mobile, activityId);
        UserPO currentUser2 = queryIndex.getCurrentUser();
        if (Objects.isNull(currentUser2)) {
            CaptchaRequest captchaRequest = new CaptchaRequest();
            captchaRequest.setMobile(mobile);
            captchaRequest.setRandStr(queryIndex.getRandStr());
            captchaRequest.setTicket(queryIndex.getTicket());
            captchaRequest.setUserIp(queryIndex.getRemoteIp());
            captchaRequest.setCaptchaAppId(199561048L);
            captchaRequest.setCaptchaAppSecretKey("Q3UaFJhDIpcUtuqrwaB6lTXg0");
            tencentCloudCaptchaService.checkCaptcha(captchaRequest);
        } else {
            mobile = currentUser2.getMobile();
        }
        QueryJinShuJuIndexDTO dto = jinShuJuActivityService.queryIndex(activityId);
        Query query = new Query();
        query.addCriteria(Criteria.where("mobile").is(mobile));
        H5UserPO user = this.mongoTemplate.findOne(query, H5UserPO.class);
        if (Objects.isNull(user)) {
            return new QueryUserJinShuJuResultDTO();
        }
        QueryUserJinShuJuResultDTO result = new QueryUserJinShuJuResultDTO();
        result.setStop(dto.getStop());
        result.setStopDetail(dto.getStopDetail());
        result.setStatus(dto.getStatus());
        UserPO currentUser = new UserPO();
        currentUser.setMobile(mobile);
        JinShuJuUserTranscriptDTO userQaTranscript = jinShuJuQaService.findUserQaTranscriptByActivityId(activityId, currentUser);
        //未报名
        if (!userQaTranscript.getJoined()) {
            return result;
        }
        result.setOpenId(user.getOpenId());
        result.setJoined(Boolean.TRUE);
        result.setPassed(userQaTranscript.getPassed());
        return result;
    }

    public JinUserJoinInfoDTO getJoinInfo(JinUserInfoQueryVo queryVo) {
        JinUserJoinInfoDTO userInfo = new JinUserJoinInfoDTO();
        String activityId = queryVo.getActivityId();
        userInfo.setHasJoin(false);
        if ("wechat-h5".equals(queryVo.getPlatform()) && StringUtils.isNotBlank(queryVo.getOpenId())) {
            String openId = queryVo.getOpenId();
            WechatH5UserPO wechatH5UserPO = cacheUserService.findByOpenId("", openId);
            if (wechatH5UserPO == null) {
                throw new BusinessException("微信信息不存在");
            }
            JinUserBindInfo bindInfo = findBindMobile(openId);
            if (bindInfo != null) {
                JinUserParticipate participate = findJinJoinInfo(activityId, bindInfo.getMobile());
                if (participate != null) {
                    userInfo.setHasJoin(true);
                    userInfo.setOpenId("h5-" + participate.getMobile());
                    userInfo.setScore(participate.getScore());
                    // 是否通过
                    userInfo.setPassed(isPass(activityId, participate.getScore()));
                }
            }
        }
        return userInfo;
    }

    /**
     * 查询用户信息是否存在
     * 如果 存在报名信息 手动报名
     *
     * @param queryVo
     * @return
     */
    public JinUserResInfoDTO queryUserInfo(JinUserInfoQueryVo queryVo) {
        log.info(":>>> 查询金数据用户:{}", JSON.toJSON(queryVo));
        JinUserResInfoDTO userInfo = new JinUserResInfoDTO();
        String activityId = queryVo.getActivityId();
        userInfo.setHasUserInfo(false);
        boolean isWechat = "wechat-h5".equals(queryVo.getPlatform());
        String openId = isWechat ? queryVo.getOpenId() : "";
        if (queryVo.getScore() == null) {
            throw new BusinessException("答题分数不能为空");
        }
        String subAppId = activitySubscribeAppIdService.getActivitySubscribeAppIdByActivityId(activityId);
        if (StringUtils.isBlank(subAppId)) {
            subAppId = queryVo.getAppId();
        }
        userInfo.setSubAppId(subAppId);
        ActivityInfo activityInfo = activityService.findOne(activityId);
        if (Objects.isNull(activityInfo)) {
            throw new BusinessException("活动不存在");
        }
        boolean isLogin = queryVo.getUserPO() != null;
        log.info(":>>> openId:{},appId:{},用户是否登录:{}", queryVo.getOpenId(), queryVo.getAppId(), isLogin);
        if (isLogin) {
            // 登录之后添加报名信息
            UserPO userPO = queryVo.getUserPO();
            log.info(":>>> openId:{},appId:{},用户登录状态,用户信息:{}", queryVo.getOpenId(), queryVo.getAppId(), JSON.toJSON(userPO));
            if (!StringUtils.isAnyBlank(userPO.getUniversityName(), userPO.getName())) {
                userInfo.setHasUserInfo(true);
                userInfo.setOpenId(userPO.getOpenId());
//                userInfo.setOpenId(queryVo.getOpenId());
                UserParticipateInfoDTO dto = buildUserParticipate(userPO);
                dto.setActivityId(activityId);
                dto.setPlatform(queryVo.getPlatform());
                dto.setOpenId(queryVo.getOpenId());
                dto.setAppId(queryVo.getAppId());
                // 添加/更新报名
                JinUserJoinDTO re = upsertParticipate(dto, userPO.getId(), queryVo.getScore());
                if (re.getIsFirst()) {
                    activityService.updateActivityJoinNum(activityId, 1, new Date());
                    userParticipateActivityInfoService.increJoinedCount(activityId, 1L);
                    if (StringUtils.isNotBlank(queryVo.getChannel())) {
                        activityChannelStatisticsService.setSignUpChannel(activityInfo.getId(), queryVo.getChannel());
                    }
                }
                userInfo.setIsFirst(re.getIsFirst());
                // 添加邀请记录
                addInviteAndRank(re.getIsFirst(), activityId, queryVo.getShareUserId(), userPO.getId(), openId);
                // 是否通过
                userInfo.setPassed(isPass(activityId, re.getScore()));
                userInfo.setAppId(queryVo.getAppId());
                log.info(":>>> openId:{},appId:{},大学名和名字不为空:{}", queryVo.getOpenId(), queryVo.getAppId(), JSON.toJSON(userInfo));
                return userInfo;
            }
        } else {
            log.info(":>>> openId:{},appId:{},用户登录未状态", queryVo.getOpenId(), queryVo.getAppId());
            if (isWechat && StringUtils.isNotBlank(queryVo.getOpenId())) {
                WechatH5UserPO wechatH5UserPO = cacheUserService.findByOpenId("", openId);
                if (wechatH5UserPO == null) {
                    log.info(":>>> wechatH5用户不存在,openId:{},appId:{}", openId, queryVo.getAppId());
                    throw new BusinessException("微信用户不存在");
                }
                H5UserPO userPO = findUserInfoByOpenId(openId);
                // 金数据平台存在用户信息,手动报名
                if (userPO != null) {
                    userInfo.setHasUserInfo(true);
                    userInfo.setOpenId(userPO.getOpenId());
//                    userInfo.setOpenId(queryVo.getOpenId());
                    UserParticipateInfoDTO dto = buildUserParticipate(userPO);
                    dto.setActivityId(activityId);
                    dto.setPlatform(queryVo.getPlatform());
                    dto.setOpenId(queryVo.getOpenId());
                    dto.setAppId(queryVo.getAppId());
                    // 添加/更新报名
                    JinUserJoinDTO re = upsertParticipate(dto, userPO.getAccountInfoId(), queryVo.getScore());
                    if (re.getIsFirst()) {
                        activityService.updateActivityJoinNum(activityId, 1, new Date());
                        userParticipateActivityInfoService.increJoinedCount(activityId, 1L);
                        if (StringUtils.isNotBlank(queryVo.getChannel())) {
                            activityChannelStatisticsService.setSignUpChannel(activityInfo.getId(), queryVo.getChannel());
                        }
                    }
                    userInfo.setIsFirst(re.getIsFirst());
                    // 是否通过
                    userInfo.setPassed(isPass(activityId, re.getScore()));
                    //添加邀请记录
                    addInviteAndRank(re.getIsFirst(), activityId, queryVo.getShareUserId(), userPO.getAccountInfoId(), openId);
                    return userInfo;
                }
                // 其他平台报名了,手动报名
                UserParticipateActivityInfo participate = this.findParticipateByUserId(wechatH5UserPO.getAccountInfoId());
                if (participate != null && !StringUtils.isAnyBlank(participate.getMobile(), participate.getUniversityName())) {
                    UserParticipateInfoDTO dto = buildUserParticipate(participate);
                    dto.setActivityId(activityId);
                    dto.setPlatform(queryVo.getPlatform());
                    dto.setOpenId(queryVo.getOpenId());
                    dto.setAppId(queryVo.getAppId());
                    // 保存用户信息
                    userPO = saveH5User(dto);
                    // 添加/更新报名
                    JinUserJoinDTO re = upsertParticipate(dto, userPO.getAccountInfoId(), queryVo.getScore());
                    if (re.getIsFirst()) {
                        activityService.updateActivityJoinNum(activityId, 1, new Date());
                        userParticipateActivityInfoService.increJoinedCount(activityId, 1L);
                        if (StringUtils.isNotBlank(queryVo.getChannel())) {
                            activityChannelStatisticsService.setSignUpChannel(activityInfo.getId(), queryVo.getChannel());
                        }
                    }
                    // 是否通过
                    userInfo.setPassed(isPass(activityId, re.getScore()));
                    // 绑定用户信息
                    bindUserInfo(participate.getMobile(), openId, userPO.getAccountInfoId());
                    userInfo.setIsFirst(re.getIsFirst());
                    // 添加邀请记录
                    addInviteAndRank(re.getIsFirst(), activityId, queryVo.getShareUserId(), userPO.getAccountInfoId(), openId);
                    userInfo.setHasUserInfo(true);
                    userInfo.setOpenId(userPO.getOpenId());
                    return userInfo;
                }
            }
        }
        return userInfo;
    }

    /**
     * 添加排行榜
     *
     * @param isFirst
     * @param activityId
     * @param shareUserId
     * @param currentUserId
     * @param openId
     */
    public void addInviteAndRank(boolean isFirst, String activityId, String shareUserId, String currentUserId, String openId) {
        if (isFirst && StringUtils.isNotBlank(shareUserId)) {
            //添加邀请记录
            boolean addSuccess = jinShuJuUserInviteService.addInviteRecord(activityId, shareUserId, currentUserId);
            if (addSuccess) {
                // 添加/修改 排行榜分数
                jinShuJuUserRankService.saveUserRankRecord(activityId, shareUserId, 1);
            }
        } else {
            if (StringUtils.isNotBlank(openId)) {
                jinShuJuUserRankService.updateOpenId(activityId, currentUserId, openId);
            }
        }
    }

    /**
     * 获取微信信息授权和id
     *
     * @return
     */
    public JinUserWechatVO findWechatInfo(UserPO user, String platform) {
        JinUserWechatVO jinUserWechatVO = new JinUserWechatVO();
        jinUserWechatVO.setAvatarUrl(user.getAvatarUrl());
        boolean isNotWechat = !"wechat-h5".equals(platform);
        jinUserWechatVO.setNickName("匿名用户");
        jinUserWechatVO.setAuthorized(isNotWechat);
        Query query = new Query();
        query.addCriteria(Criteria.where("mobile").is(user.getMobile()));
        JinUserBindInfo bindInfo = mongoTemplate.findOne(query, JinUserBindInfo.class);
        if (bindInfo != null) {
            WechatH5UserPO wechatH5UserPO = cacheUserService.findByOpenId("", bindInfo.getThirdCode());
            if (wechatH5UserPO != null) {
                String logoUrl = wechatH5UserPO.getAvatarUrl();
                boolean hasLogo = StringUtils.isNotBlank(wechatH5UserPO.getAvatarUrl()) && !logoUrl.startsWith("https://thirdwx.qlogo.cn");
                jinUserWechatVO.setAuthorized(isNotWechat || hasLogo);
                if (hasLogo) {
                    jinUserWechatVO.setAvatarUrl(wechatH5UserPO.getAvatarUrl());
                }
                jinUserWechatVO.setNickName(wechatH5UserPO.getNickName());
            }
        }
        return jinUserWechatVO;
    }

    public boolean isPass(String activityId, Double score) {
        ActivityQaInfo activityQaInfo = activityQaInfoService.findByActivityIdAndQaNumber(activityId, 1);
        return score.compareTo(activityQaInfo.getPassQaScore()) >= 0;
    }


    public void updateScore(String id, Double score) {
        Query query = new Query(Criteria.where("id").is(id));
        Update update = new Update();
        update.set("score", score);
        update.set("qaTime", new Date());
        this.mongoTemplate.updateFirst(query, update, JinUserParticipate.class);
    }

    public void updateScoreByActivityId(String activityId, String mobile, Double score) {
        Query query = new Query(Criteria.where("activityId").is(activityId).and("mobile").is(mobile).and("score").lt(score));
        Update update = new Update();
        update.set("score", score);
        update.set("qaTime", new Date());
        this.mongoTemplate.updateFirst(query, update, JinUserParticipate.class);
    }

    /**
     * 添加报名信息
     *
     * @param req
     * @return
     */
    public JinUserResInfoDTO addUserParticipate(JinUserParticipateDTO req) {
        log.info("add jin shu ju Participate:{}", JSON.toJSONString(req));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getMobile()) || StringUtils.isBlank(req.getCode())) {
            throw new BusinessException("手机验证码登陆参数错误");
        }
        if (StringUtils.isEmpty(req.getActivityId())) {
            throw new BusinessException("活动Id不能为空");
        }
        if (StringUtils.isAnyBlank(req.getName(), req.getUniversityName(), req.getUniversityId())) {
            throw new BusinessException("参数不能为空");
        }
        ActivityInfo activityInfo = activityService.findOne(req.getActivityId());
        if (Objects.isNull(activityInfo)) {
            throw new BusinessException("活动不存在");
        }
        SmsBaseInfoDTO dto = SmsBaseInfoDTO.builder().phone(req.getMobile()).code(req.getCode()).build();
        Pair<Boolean, String> result = smsServerService.checkVerifyCode(dto);
        if (!result.getLeft()) {
            throw new BusinessException(result.getRight());
        }
        H5UserPO saveH5User = saveH5User(req);
        JinUserResInfoDTO userResponse = new JinUserResInfoDTO();
        userResponse.setOpenId(saveH5User.getOpenId());
        userResponse.setHasUserInfo(true);
        userResponse.setIsFirst(false);
        String activityId = req.getActivityId();
        boolean isWechat = "wechat-h5".equals(req.getPlatform());
        if (isWechat && StringUtils.isNotBlank(req.getOpenId())) {
            String openId = req.getOpenId();
            WechatH5UserPO wechatH5UserPO = cacheUserService.findByOpenId("", openId);
            if (wechatH5UserPO == null) {
                throw new BusinessException("微信信息不存在");
            }
            // 添加绑定信息
            bindUserInfo(saveH5User.getMobile(), req.getOpenId(), saveH5User.getAccountInfoId());
        }
        // 添加/更新报名
        JinUserJoinDTO re = upsertParticipate(req, saveH5User.getAccountInfoId(), req.getScore());
        userResponse.setIsFirst(re.getIsFirst());
        if (re.getIsFirst()) {
            activityService.updateActivityJoinNum(activityId, 1, new Date());
            userParticipateActivityInfoService.increJoinedCount(activityId, 1L);
            if (StringUtils.isNotBlank(req.getChannel())) {
                activityChannelStatisticsService.setSignUpChannel(activityInfo.getId(), req.getChannel());
            }
        }
        // 是否通过
        userResponse.setPassed(isPass(activityId, re.getScore()));
        String openId = isWechat ? req.getOpenId() : "";
        // 添加邀请记录
        addInviteAndRank(re.getIsFirst(), activityId, req.getShareUserId(), saveH5User.getAccountInfoId(), openId);
        return userResponse;
    }


    /**
     * 添加/更新报名记录
     *
     * @param req
     * @param userId
     * @param score
     * @return
     */
    public JinUserJoinDTO upsertParticipate(UserParticipateInfoDTO req, String userId, Double score) {
        JinUserJoinDTO dto = new JinUserJoinDTO();
        dto.setIsFirst(false);
        Date now = new Date();
        JinUserParticipate jinUserParticipate = findJinJoinInfo(req.getActivityId(), req.getMobile());
        if (jinUserParticipate == null) {
            jinUserParticipate = savaJinUserParticipateInfo(req, userId, score);
            dto.setScore(score);
            if (jinUserParticipate.getVersion() == 1) {
                jinUserParticipate.setScore(score);
                jinUserParticipate.setQaTime(now);
                jinShuJuQaService.setCacheUserInfo(jinUserParticipate);
                dto.setIsFirst(true);
            }
            return dto;
        }
        dto.setScore(jinUserParticipate.getScore());
        // 更新答题分数
        if (score.compareTo(jinUserParticipate.getScore()) > 0) {
            updateScore(jinUserParticipate.getId(), score);
            jinUserParticipate.setScore(score);
            jinUserParticipate.setQaTime(now);
            jinShuJuQaService.setCacheUserInfo(jinUserParticipate);
            dto.setScore(score);
        }
        return dto;
    }

    /**
     * 保存报名信息
     *
     * @param dto
     * @param userId
     * @param score
     * @return
     */
    public JinUserParticipate savaJinUserParticipateInfo(UserParticipateInfoDTO dto, String userId, Double score) {
        Query query = new Query();
        query.addCriteria(Criteria.where("mobile").is(dto.getMobile()));
        query.addCriteria(Criteria.where("activityId").is(dto.getActivityId()));
        Update update = new Update();
        Date date = new Date();
        update.set("userId", userId);
        update.inc("version", 1);
        if (StringUtils.isNotBlank(dto.getName())) {
            update.set("name", dto.getName());
        }
        if (StringUtils.isNotBlank(dto.getUniversityId())) {
            update.set("universityId", dto.getUniversityId());
        }
        if (StringUtils.isNotBlank(dto.getUniversityName())) {
            update.set("universityName", dto.getUniversityName());
        }
        if ("wechat-h5".equals(dto.getPlatform()) && StringUtils.isNotBlank(dto.getOpenId())) {
            update.set("openId", dto.getOpenId());
            update.set("appId", dto.getAppId());
        }
        update.set("updatedTime", date);
        update.setOnInsert("createdTime", date);
        update.set("platform", dto.getPlatform());
        update.setOnInsert("qaTime", date);
        update.setOnInsert("signUpTime", date);
        score = score == null ? 0 : score;
        update.set("score", score);
        FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
        findAndModifyOptions.returnNew(Boolean.TRUE);
        findAndModifyOptions.upsert(Boolean.TRUE);
        return mongoTemplate.findAndModify(query, update, findAndModifyOptions, JinUserParticipate.class);
    }


    public UserParticipateInfoDTO buildUserParticipate(UserParticipateActivityInfo participate) {
        UserParticipateInfoDTO dto = new UserParticipateInfoDTO();
        dto.setMobile(participate.getMobile());
        dto.setName(participate.getName());
        dto.setUniversityId(participate.getUniversityId());
        dto.setUniversityName(participate.getUniversityName());
        return dto;
    }

    public UserParticipateInfoDTO buildUserParticipate(H5UserPO userPO) {
        UserParticipateInfoDTO dto = new UserParticipateInfoDTO();
        dto.setMobile(userPO.getMobile());
        dto.setName(userPO.getName());
        dto.setUniversityId(userPO.getUniversityId());
        dto.setUniversityName(userPO.getUniversityName());
        return dto;
    }

    public UserParticipateInfoDTO buildUserParticipate(UserPO userPO) {
        UserParticipateInfoDTO dto = new UserParticipateInfoDTO();
        dto.setMobile(userPO.getMobile());
        dto.setName(userPO.getName());
        dto.setUniversityId(userPO.getUniversityId());
        dto.setUniversityName(userPO.getUniversityName());
        return dto;
    }

    /**
     * 将手机号构建到用户信息表
     *
     * @param dto
     * @return
     */
    public H5UserPO saveH5User(UserParticipateInfoDTO dto) {
        String openId = "h5-" + dto.getMobile();
        UserPO userPO = visitorUserService.getUserByOpenId(openId);
        Date date = new Date();
        if (userPO == null) {
            userPO = new UserPO();
            userPO.setId(null);
            userPO.setOpenId(openId);
            userPO.setCreatedTime(new Date());
            userPO.setCheckedMobile(true);
            userPO.setMobile(dto.getMobile());
            userPO.setCheckedMobileTime(date);
            userPO.setName(dto.getName());
            userPO.setUniversityId(dto.getUniversityId());
            userPO.setUniversityName(dto.getUniversityName());
            userPO = mongoTemplate.insert(userPO);
        }
        Query queryAppUser = new Query().addCriteria(Criteria.where("openId").is(openId));
        H5UserPO appUserPO = mongoTemplate.findOne(queryAppUser, H5UserPO.class);
        if (Objects.isNull(appUserPO)) {
            appUserPO = new H5UserPO();
            appUserPO.setId(null);
            appUserPO.setAccountInfoId(userPO.getId());
            appUserPO.setCheckedMobile(true);
            appUserPO.setOpenId(userPO.getOpenId());
            appUserPO.setCreatedTime(date);
            appUserPO.setCheckedMobile(true);
            appUserPO.setMobile(dto.getMobile());
            appUserPO.setCheckedMobileTime(date);
            appUserPO.setLoginTime(date);
            appUserPO.setName(dto.getName());
            appUserPO.setUniversityId(dto.getUniversityId());
            appUserPO.setUniversityName(dto.getUniversityName());
            SystemNickNameAndHeaderImage image = systemNickNameAndHeaderImageService.getRandom();
            appUserPO.setAvatarUrl(image.getAvatarUrl());
            appUserPO.setNickName(image.getNickName());
            appUserPO.setName(dto.getName());
            appUserPO = mongoTemplate.insert(appUserPO);
        } else {
            appUserPO.setAccountInfoId(userPO.getId());
            appUserPO.setName(dto.getName());
            appUserPO.setUniversityId(dto.getUniversityId());
            appUserPO.setUniversityName(dto.getUniversityName());
            if (StringUtils.isEmpty(appUserPO.getAvatarUrl())) {
                SystemNickNameAndHeaderImage image = systemNickNameAndHeaderImageService.getRandom();
                appUserPO.setAvatarUrl(image.getAvatarUrl());
                appUserPO.setNickName(image.getNickName());
            }
            appUserPO.setUpdatedTime(date);
            mongoTemplate.save(appUserPO);
        }
        return appUserPO;
    }

    public void bindUserInfo(String mobile, String thirdCode, String userId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("thirdCode").is(thirdCode));
        query.addCriteria(Criteria.where("mobile").is(mobile));
        Date date = new Date();
        Update update = new Update();
        update.setOnInsert("createdTime", date);
        update.setOnInsert("userId", userId);
        update.set("updatedTime", date);
        FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
        findAndModifyOptions.returnNew(Boolean.TRUE);
        findAndModifyOptions.upsert(Boolean.TRUE);
        mongoTemplate.findAndModify(query, update, findAndModifyOptions, JinUserBindInfo.class);
    }


    public JinUserBindInfo findBindMobile(String openId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("thirdCode").is(openId));
        JinUserBindInfo bindInfo = mongoTemplate.findOne(query, JinUserBindInfo.class);
        return bindInfo;

    }

    public H5UserPO findUserInfoByOpenId(String openId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("thirdCode").is(openId));
        JinUserBindInfo bindInfo = mongoTemplate.findOne(query, JinUserBindInfo.class);
        if (bindInfo == null) {
            return null;
        }
        Query query1 = new Query(Criteria.where("openId").is("h5-" + bindInfo.getMobile()));
        H5UserPO h5UserPO = mongoTemplate.findOne(query1, H5UserPO.class);
        return h5UserPO;
    }

    public JinUserParticipate findJinJoinInfo(String activityId, String mobile) {
        Query query = new Query();
        query.addCriteria(Criteria.where("activityId").is(activityId));
        query.addCriteria(Criteria.where("mobile").is(mobile));
        return mongoTemplate.findOne(query, JinUserParticipate.class);
    }

    public JinUserParticipate findJinJoinInfoByActivityId(String activityId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("activityId").is(activityId));
        return mongoTemplate.findOne(query, JinUserParticipate.class);
    }


    public UserParticipateActivityInfo findParticipateByUserId(String userId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.addCriteria(Criteria.where("joined").is(Boolean.TRUE));
        query.with(Sort.by(Sort.Direction.DESC, "id"));
        return mongoTemplate.findOne(query, UserParticipateActivityInfo.class);
    }

    /**
     * 修改用户手机号
     *
     * @param id
     * @param mobile
     * @return
     */
    public boolean updateMobile(String id, String mobile) {
        log.info(":>>> 开始更新金数据活动报名手机号:{},{}", id, mobile);
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(id));
        JinUserParticipate data = mongoTemplate.findOne(query, JinUserParticipate.class);
        if (Objects.isNull(data) || !StringUtils.isNotBlank(data.getMobile())) {
            log.error(":>>> 金数据报名信息不存在:{}", id);
            return false;
        }
        Update update = new Update();
        update.set("mobile", mobile);
        update.set("updatedTime", new Date());
        UpdateResult updateResultP = mongoTemplate.updateFirst(query, update, JinUserParticipate.class);
        log.info(":>>> 更新金数据报名信息手机号,ID:{},原手机号:{},修改为手机号:{},结果:{}",
                id, data.getMobile(), mobile, updateResultP.getMatchedCount() > 0 ? true : false);
        //  更新用户表
        Query queryH5 = new Query();
        queryH5.addCriteria(Criteria.where("mobile").is(data.getMobile()));
        Update updateH5 = new Update();
        updateH5.set("mobile", mobile);
        updateH5.set("updatedTime", new Date());
        mongoTemplate.updateMulti(queryH5, updateH5, H5UserPO.class);

        // 更新绑定账户表
        Query queryH5Bind = new Query();
        queryH5Bind.addCriteria(Criteria.where("mobile").is(data.getMobile()));
        Update updateH5Bind = new Update();
        updateH5Bind.set("mobile", mobile);
        updateH5Bind.set("updatedTime", new Date());
        mongoTemplate.updateMulti(queryH5Bind, updateH5Bind, JinUserBindInfo.class);
        return true;

    }
}
